﻿using System;
using System.Data;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Dimok;
using Dimok.Shared;
using Dimok.Shared.Web;
using Dimok.Web.UI;

[DataContract]
	public class Profiler :Dimok.Web.IProfiler {
		//#region Dictionaries
		//public class Pages : SerializableDictionary<string, UserSettings.Page> { }
		//public class Grids : SerializableDictionary<string, UserSettings.Page.Grid> { }
		//public class Reports : SerializableDictionary<string, UserSettings.Page.Grid.Report> { }
		//public class Docks : SerializableDictionary<string, UserSettings.Page.Grid.Report.Dock> { }
		//public class Filters : SerializableDictionary<string, UserSettings.Page.Grid.Report.Filter> { }
		//public class Sorts : SerializableDictionary<string, UserSettings.Page.Grid.Report.Sort> { }
		//public class Details : SerializableDictionary<string, UserSettings.Page.Grid.Report.Detail> { }
		//#endregion
		public static Object ProfileLock = new Object();
		public const string DEFAULT_CONTROL_ID = "";
		private static List<ProfileCommon> CachedProfiles = new List<ProfileCommon>();
		#region Properties
		public const string DEFAULT_REPORT_NAME = "";
		public ProfileCommon profile;
		PageSettingsDS.PageRow pageRow;
		PageSettingsDS.GridViewRow gridViewRow;
		public string pageType;
		public string controlID = DEFAULT_CONTROL_ID;
		private static UserSettings.Page GetPage(ProfileCommon Profile, string PageType) { return Profile.UserSettings.Pages.EnsureValue(PageType); }
		private static UserSettings.Page.Grid GetGrid(ProfileCommon Profile, string PageType, string ControlID) { return GetPage(Profile, PageType).Grids.EnsureValue(ControlID); }
		private static UserSettings.Page.Grid.Report GetReport(ProfileCommon Profile, string PageType, string ControlID,string ReportName) {
			if ((ControlID + "") == "") throw new MissingFieldException("Report cannot belong to empty ControlID.");
			ReportName = (ReportName + "").Default(DEFAULT_REPORT_NAME);
			var report = GetGrid(Profile, PageType,ControlID).Reports.EnsureValue(ReportName);
			if (report.Name == null) report.Name = ReportName;
			return report;
		}
		public UserSettings.Page Page { get { return GetPage(profile, pageType); } }
		public UserSettings.Page.Grid Grid { get { return GetGrid(profile, pageType,controlID); } }
		public UserSettings.Page.Grid.Report Report(string ReportName) { return GetReport(profile, pageType, controlID, ReportName); }
		public UserSettings.Page.Grid.Report Report() { return GetReport(profile, pageType, controlID, ""); }
		public UserSettings.Page.Grid.Report[] Reports() { return GetGrid(profile, pageType, controlID).Reports.Values.ToArray(); }
		public string[] ReportNames() { return Reports().Select(r=>r.Name).ToArray(); }
		#endregion

		#region Constructors
		//public Profiler(string PageType) : this(GetProfile(), PageType) { }
		public Profiler() { }
		public Profiler(string PageType, string ControlID) : this(GetProfile(), PageType, ControlID) { }
		public Profiler(string UserName, string PageType, string ControlID) : this(GetProfile(UserName), PageType, ControlID) { }
		public Profiler(System.Web.Profile.ProfileBase Profile, string PageType) : this(Profile as ProfileCommon, PageType, DEFAULT_CONTROL_ID) { }
		public Profiler(ProfileCommon Profile, string PageType) : this(Profile, PageType, DEFAULT_CONTROL_ID) { }
		public Profiler(ProfileCommon Profile, string PageType, string ControlID) {
			this.profile = Profile;
			this.pageType = PageType;
			this.controlID = ControlID;
		}
		public Profiler(Page Page) : this(GetProfile(), Page, null) { }
		public Profiler(Control Control) : this(GetProfile(), Control.Page, Control) { }
		public Profiler(Page Page, Control Control) : this(GetProfile(), Page, Control) { }
		public Profiler(string userName, Control page, Control control)	: this(GetProfile(userName),page,control) {}
		public Profiler(ProfileCommon profile, Control page, Control control) {
			this.profile = profile;
			this.pageType = page.GetType().Name;
			if (control != null) this.controlID = typeof(RadGridExtender).IsInstanceOfType(control) ? ((RadGridExtender)control).ProfileID : control.ClientID;
		}
		[MethodImpl(MethodImplOptions.Synchronized)]
		public static ProfileCommon GetProfile() { return HttpContext.Current.Profile as ProfileCommon; }
		public static ProfileCommon GetProfile(string UserName) { return new ProfileCommon().GetProfile(UserName); }
		#endregion



		#region Report

		public string Report_FindName() {
			var report = from p1 in Grid.Reports.Where(r => r.Key == Profiler.DEFAULT_REPORT_NAME)
							join p2 in Grid.Reports.Where(r => r.Key != Profiler.DEFAULT_REPORT_NAME)
							on p1.Value.FilterLinq equals p2.Value.FilterLinq
							select p2.Key;
			return report.Count() > 0 ? report.ToArray()[0] : "";
		}
		
		public void Report_Copy(string ReportNameFrom, string ReportNameTo) {
			if (ReportNameFrom + "" == "") ReportNameFrom = DEFAULT_REPORT_NAME;
			if (ReportNameTo + "" == "") ReportNameTo = DEFAULT_REPORT_NAME;
			if (ReportNameFrom == ReportNameTo) return;
			Grid.Reports[ReportNameTo] = Grid.Reports[ReportNameFrom];
			Save();
		}

		#region Delete
		public void Report_Delete( string ReportName) {
			Report_Delete(profile, pageType, controlID, ReportName);
		}
		public static void Report_Delete(ProfileCommon Profile,string PageType,string ControlID, string ReportName){
			GetGrid(Profile, PageType, ControlID).Reports.Remove(ReportName);
			Profile.Save();
		}
		#endregion
		
		#endregion

		#region GridViewDetailColumns
		public void Details_Sync( ) {
			var dictColumns = Details(profile, pageType, controlID, "").
				Select(s => new { ColumnName = s.Key, ColumnPosition = s.Value.ColumnPosition }).
				ToDictionary(s => s.ColumnName, s => s.ColumnPosition);
			var dictDocks = Docks(profile, pageType, controlID, "").
				Select(s => new { DockName = s.Key, Children = s.Value.Children.Split('\n') }).
				ToDictionary(s => s.DockName, s => s.Children);
			var reportDefault = GetReport(profile, pageType, controlID,"");
			var reports = from r1 in GetGrid(profile,pageType,controlID).Reports.Where(s=>s.Key!=DEFAULT_REPORT_NAME)
										join r2 in GetGrid(profile, pageType, controlID).Reports.Where(s => s.Key == DEFAULT_REPORT_NAME)
										on r1.Value.FilterLinq equals r2.Value.FilterLinq
										select r1;
			foreach (var r in reports) {
				Details_Update(profile, pageType, controlID, r.Key, dictColumns);
				r.Value.DetailViewXYWH = reportDefault.DetailViewXYWH;
				r.Value.Columns = reportDefault.Columns;
				Docks_Add(profile, pageType, controlID, r.Key, dictDocks);
			}
			Save();
		}
		#region Get
		public SerializableDictionary<string, UserSettings.Page.Grid.Report.Detail> Details(string ReportName, string DefaultDetailColumns) {
			var rows = Details(profile, pageType, controlID, ReportName);
			if (rows.Count == 0 && DefaultDetailColumns + "" != "") {
				var pos = 100;
				return new SerializableDictionary<string, UserSettings.Page.Grid.Report.Detail>(
					DefaultDetailColumns.Split(',').ToDictionary(s => s, s => new UserSettings.Page.Grid.Report.Detail(pos++)));
			}
			return rows;
		}
		public SerializableDictionary<string, UserSettings.Page.Grid.Report.Detail> Details(string ReportName) {
			return Details(profile, pageType, controlID, ReportName);
		}
		protected static SerializableDictionary<string, UserSettings.Page.Grid.Report.Detail> Details(ProfileCommon profile, string PageType, string ControlID, string ReportName) {
			return GetReport(profile, PageType, ControlID, ReportName).Details;
		}
		#endregion
		#region Update
		public void Details_Update(string reportName, Hashtable detailColumns) {
			Dictionary<string, int> dict = new Dictionary<string, int>();
			foreach (DictionaryEntry de in detailColumns)
				dict.Add(de.Key + "", int.Parse(de.Value+""));
			Details_Update(profile, pageType, controlID, reportName, dict);
		}
		public void Details_Update(string reportName, Dictionary<string, int> detailColumns) {
			 Details_Update(profile, pageType, controlID, reportName, detailColumns);
		}
		protected static void Details_Update
			(ProfileCommon profile, string pageType, string controlID, string reportName, Dictionary<string, int> detailColumns) {
			GetReport(profile, pageType, controlID, reportName).Details = new SerializableDictionary<string, UserSettings.Page.Grid.Report.Detail>(
					detailColumns.ToDictionary(d=>d.Key,d=>new UserSettings.Page.Grid.Report.Detail(d.Value))
				);
			Save(profile);
		}
		#endregion
		#endregion

		#region SortExpression
		#region Get
		public SerializableDictionary<string, UserSettings.Page.Grid.Report.Sort> Sorts(string ReportName) {
			return GetReport(profile, pageType, controlID, ReportName).Sorts;
		}
		protected static SerializableDictionary<string, UserSettings.Page.Grid.Report.Sort> Sorts(ProfileCommon profile, string pageType, string controlID, string reportName) {
			return GetReport(profile, pageType, controlID, reportName).Sorts;
		}
		#endregion
		#region Add
		public SerializableDictionary<string, UserSettings.Page.Grid.Report.Sort> Sorts_Add(string reportName, Dictionary<string, int> sortExpressions) {
			return Sorts_Add(profile, pageType, controlID, reportName, sortExpressions.ToDictionary(d=>d.Key,d=>(ListSortDirection)d.Value));
		}
		public Dictionary<string, UserSettings.Page.Grid.Report.Sort> Sorts_Add(string reportName, Dictionary<string, ListSortDirection> sortExpressions) {
			return Sorts_Add(profile, pageType, controlID, reportName, sortExpressions);
		}
		protected static SerializableDictionary<string, UserSettings.Page.Grid.Report.Sort> Sorts_Add
			(ProfileCommon profile, string pageType, string controlID, string reportName, Dictionary<string, ListSortDirection> sortExpressions) {
			if (controlID + "" == "") throw new MissingFieldException("ControlID is empty in Profiler.");
			if (reportName + "" == "") reportName = DEFAULT_REPORT_NAME;
			GetReport(profile,pageType,controlID,reportName).Sorts = 
				new Dimok.SerializableDictionary<string, UserSettings.Page.Grid.Report.Sort>(
					sortExpressions.ToDictionary(d => d.Key, d => new UserSettings.Page.Grid.Report.Sort((ListSortDirection)d.Value)));
			//var dt = profile.PageSettings.SortExpressions;
			//foreach (PageSettingsDS.SortExpressionsRow row in GridViewReportRow(profile, pageType, controlID,reportName).GetSortExpressionsRows())
			//  row.Delete();
			//foreach (var exp in sortExpressions.Where(s=>s.Value > 0))
			//  dt.AddSortExpressionsRow(controlID, pageType, reportName, exp.Key, exp.Value);
			//dt.AcceptChanges();
			profile.Save();
			return GetReport(profile, pageType, controlID, reportName).Sorts;
		}
		#endregion
		#endregion

		#region Docks
		public SerializableDictionary<string,UserSettings.Page.Grid.Report.Dock> Docks(string ReportName) {
			return Docks(profile, pageType, controlID, ReportName);
		}
		static SerializableDictionary<string, UserSettings.Page.Grid.Report.Dock> Docks(ProfileCommon profile, string pageType, string controlID, string reportName) {
			return GetReport(profile, pageType, controlID, reportName).Docks;
		}
		public void Docks_Add(string ReportName, Hashtable Docks) {
			Dictionary<string, string[]> dict = new Dictionary<string, string[]>();
			foreach (DictionaryEntry de in Docks)
				dict.Add(de.Key + "", ((object[])de.Value).Select(s => s + "").ToArray());
			Docks_Add(profile, pageType, controlID, ReportName, dict);
		}
		public void Docks_Add(string ReportName, Dictionary<string, string[]> Docks) {
			Docks_Add(profile, pageType, controlID, ReportName, Docks);
		}
		static void Docks_Add(ProfileCommon profile, string pageType, string controlID, string reportName, Dictionary<string, string[]> docks) {
			GetReport(profile, pageType, controlID, reportName).Docks =
				new SerializableDictionary<string, UserSettings.Page.Grid.Report.Dock>(
					docks.ToDictionary(d => d.Key, d => new UserSettings.Page.Grid.Report.Dock(string.Join("\n", d.Value))));
			Save(profile);
		}
		#endregion

		#region FilterExpression
		#region Get
		public SerializableDictionary<string, UserSettings.Page.Grid.Report.Filter> Filters(string ReportName) {
			return Filters(profile, pageType, controlID,ReportName); }

		static SerializableDictionary<string, UserSettings.Page.Grid.Report.Filter> Filters(ProfileCommon profile, string pageType, string controlID, string reportName) {
			return GetReport(profile, pageType, controlID, reportName).Filters;
		}
		#endregion
		#region Add
		public void Filters_Add(string ReportName) {
			Filters_Add(ReportName, new Telerik.Web.UI.GridFilterExpression[] { });
		}
		public void Filters_Add(string ReportName, Telerik.Web.UI.GridFilterExpression[] FilterExpressions) {
			Filters_Add(profile, pageType, controlID,ReportName, FilterExpressions);
		}
		public void Filters_Add(string ReportName, Dictionary<string, Dimok.Shared.Filtering.FilterQuery> FilterExpressions) {
			Filters_Add(profile, pageType, controlID, ReportName, FilterExpressions);
		}
		static void Filters_Add
	(ProfileCommon profile, string pageType, string controlID, string reportName, Dictionary<string, Dimok.Shared.Filtering.FilterQuery> FilterExpressions) {
			GetReport(profile, pageType, controlID, reportName).FilterQueries =
				new SerializableDictionary<string, Dimok.Shared.Filtering.FilterQuery>(FilterExpressions);
			Save(profile);
		}

		static void Filters_Add
	(ProfileCommon profile, string pageType, string controlID, string reportName, Telerik.Web.UI.GridFilterExpression[] FilterExpressions) {
			GetReport(profile, pageType, controlID, reportName).Filters = new SerializableDictionary<string, UserSettings.Page.Grid.Report.Filter>(
				FilterExpressions.ToDictionary(f => f.ColumnUniqueName, f => new UserSettings.Page.Grid.Report.Filter(f.FieldName, f.FieldValue, f.FilterFunction, f.DataTypeName))
			);
			Save(profile);
		}
		#endregion
		#endregion

		#region Save
		public void Save() { Save((string)null); }
		public void Save(string reportName) {
			if (reportName != null)
				this.Grid.LastReportName = reportName;
			Save(profile);
		}
		public static void Save(ProfileCommon profile) {
			//profile.PageSettings.AcceptChanges();
			//profile.Filters.AcceptChanges();
			profile.Save();
		}
		#endregion

		#region IProfiler Members

		public Dimok.Web.IProfiler Initialize(string pageType, string controlID) {
			if (profile == null) this.profile = GetProfile();
			this.pageType = pageType;
			this.controlID = controlID;
			return this;
		}

		#endregion
	}